/**
 * @file funcsigner.cpp
 * @author iam002
 * @brief 函数签名器
 * @version 0.1
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#include "funcsigner.h"
#include <cctype>
#include <filesystem>

namespace fs = std::filesystem;

// #include <boost/filesystem.hpp>
// namespace fs = boost::filesystem;

FuncSigner::FuncSigner()
{
    m_optSym = DEFAULT_OPT_SYM;
    m_argSym = DEFAULT_ARG_SYM;
    m_version = DEFAULT_VERSION;
    m_exitKeywords = DEFAULT_EXIT_KEYWORDS;    
    m_default_kind = DEFAULT_KIND;
    m_default_type = DEFAULT_TYPE;
    m_verbose = true;
}

FuncSigner::FuncSigner(const std::string &dirPath, bool verbose)
{
    m_dirPath = dirPath;
    m_verbose = verbose;
    m_optSym = DEFAULT_OPT_SYM;
    m_argSym = DEFAULT_ARG_SYM;
    m_version = DEFAULT_VERSION;
    m_exitKeywords = DEFAULT_EXIT_KEYWORDS;    
    m_default_kind = DEFAULT_KIND;
    m_default_type = DEFAULT_TYPE;
    init();
}

FuncSigner::~FuncSigner()
{
}

void FuncSigner::setArgSym(const char *argsym)
{
    if (argsym == m_optSym) {
        // LOG_ERROR("[x] setArgSym failed: argSym == optSym");
        MSG_FATAL("setArgSym failed: argSym == optSym");
    }
    else {
        m_argSym = argsym;
    }
}

void FuncSigner::setOptSym(const char *optsym)
{
    if (m_argSym == optsym) {
        // LOG_ERROR("[x] setOptSym failed: argSym == optSym");
        MSG_FATAL("setOptSym failed: argSym == optSym");
    }
    else {
        m_optSym = optsym;
    }
}

void FuncSigner::setVesion(const char *version)
{
    m_version = version;
}

void FuncSigner::setVerbose(bool verbose)
{
    m_verbose = verbose;
}

void FuncSigner::setVersion(const char *version)
{
    m_version = version;
}

void FuncSigner::setDefaultKind(const std::string &str)
{
    m_default_kind = str;
}

void FuncSigner::setDefaultType(const std::vector<std::string> &vec)
{
    m_default_type = vec;
}

bool FuncSigner::generate(const std::string &dirPath)
{
    bool isok = true;
    m_dirPath = dirPath;
    init();

    fs::path dirobj(m_dirPath);
    if (fs::exists(dirobj) == false || fs::is_directory(dirobj) == false) {
        // LOG_ERROR("[x] 工作目录路径不存在或非目录文件: " $ m_dirPath $ std::endl);
        std::cerr << "工作目录路径不存在或非目录文件: " << m_dirPath << std::endl;
        throw std::runtime_error("工作目录路径错误");
        return false;
    }

    /* 设置日志路径 */
    _IS_LOG_PATH_VALID = true;
    const std::string log_path = m_dirPath + "/funcsigner.log";
    SetLogManager(true, true, log_path.c_str());

    /* 遍历文件 */
    for (const fs::directory_entry& entry : fs::recursive_directory_iterator(dirobj)) {
        if (fs::is_regular_file(entry)) {
            if (entry.path().extension() != ".m") {
                continue;
            }

            std::string filepath = entry.path().string();
            // 需要跳过类文件夹下的其他文件
            if (isClassFolder(filepath) == false) {
                if (!addOneFuncSign(filepath) ) {
                    isok = false;
                }
            }
            else {
                // LOG_INFO("[+] Class Floder: " $ filepath $ std::endl);
                MSG_INFO("Class Folder detected: %v" $ filepath.c_str());
            }
        }
    }

    /* 写入 json 文件 */
    Json::StreamWriterBuilder builder;
    static Json::Value        def = [] {
        Json::Value def;
        Json::StreamWriterBuilder::setDefaults(&def);
        def["emitUTF8"] = true;
        return def;
    }();
    builder.settings_ = def;
    const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
    std::string outputFile = m_dirPath + "functionSignatures.json";
    // LOG_INFO("[+] output file: " $ outputFile $ std::endl);
    MSG_INFO("Ouput json: %v" $ outputFile.c_str());
    std::fstream fs;
    fs.open(outputFile.c_str(), std::ios::out);
    writer->write(m_root, &fs);
    fs.close();

    return isok;
}

// void FuncSigner::displayErrorOnMatlab(const std::string &msg)
// {
//     std::cerr << msg << std::endl;
//     throw std::runtime_error(msg);
// }
// void FuncSigner::displayWarnOnMatlab(const std::string &msg)
// {
//     std::cerr $ msg;
// }
// void FuncSigner::displayOnMatlab(const std::string &msg)
// {
//     std::cout $ msg;
// }
// const char *FuncSigner::send(const std::ostringstream &os, SendType type)
// {
//     if (type == SendType::INFO) {
//         if (m_verbose) {
          
//             std::string msg = os.str();
//             displayOnMatlab(msg);
//         }
//     }
//     else if (type == SendType::WARN) {
//         std::string msg = os.str();
//         displayWarnOnMatlab(msg);
//     }
//     else {
//         std::string msg = os.str();
//         displayErrorOnMatlab(msg);
//     }    
//     return "";
// }

/* 获取接下来的第一个非空行 */
bool FuncSigner::skipEmptyAndGetLine(std::ifstream & fin, std::string & line)
{
    line.clear();
    while (line.empty()) {
        std::getline(fin, line);
        if (fin.eof()) {
            return false;
        }
    }
    return true;
}

/* 判断文件是否为类或函数定义文件 */
bool FuncSigner::isDefineFile(std::ifstream & fin, std::string & def_name, FuncSigner::DefineType & def_type)
{
    std::string line;
    if (!skipEmptyAndGetLine(fin, line)) {
        def_name.clear();
        def_type = FuncSigner::DefineType::NONE;
        return false;
    }
    
    std::string type_name = line.substr(0, 8);
    if (type_name == "function") {
        def_type = FuncSigner::DefineType::FUNCTION;

        /* 识别“=”, 判断函数是否存在返回值 */
        int eq_pos = 8; // 8表示function后的第一个空格
        for (int i = 0; i < line.size(); ++i) {
            if (line[i] == '=') {
                eq_pos = i;
                break;
            }
        }

        /* 从空格或者等号搜寻下一个字母, 作为函数名起始字母 */
        int start_pos = eq_pos;
        while (!isalpha(line[start_pos])) {
            start_pos ++;
        }
        /* 从函数名起始字母搜寻空格, 左括号, 作为函数名的终点位置 */
        int end_pos = start_pos;
        while (end_pos < line.size() && line[end_pos] != ' ' && line[end_pos] != '(') {
            end_pos ++;
        }
        def_name = line.substr(start_pos, end_pos - start_pos);

        // LOG_INFO("[+] define name: " $ def_name $ std::endl);
        // LOG_INFO("[+] define type: function" $ std::endl);
        MSG_INFO("define name: %v, type: function" $ def_name.c_str());
    }
    else if (type_name == "classdef") {
        def_type = FuncSigner::DefineType::CLASS;
        
        /* 从空格或者等号搜寻下一个字母, 作为函数名起始字母 */
        int start_pos = 8;
        while (!isalpha(line[start_pos])) {
            start_pos ++;
        }
        /* 从函数名起始字母搜寻空格, 左括号, 作为函数名的终点位置 */
        int end_pos = start_pos;
        while (end_pos < line.size() && line[end_pos] != ' ' && line[end_pos] != '(') {
            end_pos ++;
        }
        def_name = line.substr(start_pos, end_pos - start_pos);

        // LOG_INFO("[+] define name: " $ def_name $ std::endl);
        // LOG_INFO("[+] define type: classdef" $ std::endl);
        MSG_INFO("define name: %v, type: classdef" $ def_name.c_str());
    }
    else {
        def_name.clear();
        def_type = FuncSigner::DefineType::NONE;
    }
    
    return true;
}

void removePackagePrefix(std::string & str, const std::vector<char> & prefix_list)
{
    int j = 0;
    for (int i = 0; i < str.size(); ++i) {
        bool isPrefix = false;
        for (int k = 0; k < prefix_list.size(); ++k) {
            if (str[i] == prefix_list[k]) {
                isPrefix = true;
                break;
            }
        }
        if (isPrefix == false) {
            str[j] = str[i];
            j ++;
        }
    }
    str.erase(str.begin() + j, str.end());
}

/**
 * @brief 解析文件路径
 * 
 * @param filepath m文件路径
 * @param dir_len  工作目录字符串长度（需要包含到'\'或'/'）
 * @param def_name 解析的定义名
 * @param def_prefix 返回函数签名
 * @return true 
 * @return false 
 */
bool FuncSigner::parsePath(const std::string &filepath, int dir_len, const std::string &def_name, std::string &def_prefix)
{
    // NOTE: dir_len应该包含工作目录的'/', 末尾去除.m扩展名
    const std::string prefix_str = filepath.substr(dir_len, filepath.size() - dir_len - 2);
    
    int dot_pos = -1;
    def_prefix = prefix_str;
    removePackagePrefix(def_prefix, {'+', '@'});
    for (int i = 0; i < def_prefix.size(); ++i) {
        if (def_prefix[i] == '/' || def_prefix[i] == '\\') {
            def_prefix[i] = '.';
            dot_pos = i;
        }
    }

    // LOG_INFO("[+] define prefix: " $ def_prefix $ std::endl);
    MSG_INFO("define prefix: %v" $ def_prefix);
    
    bool issame = false;
    if (def_prefix.substr(dot_pos+1, def_prefix.size()) == def_name) {
        issame = true;
    }
    
    // delete [] tmp;
    return issame;
}

void FuncSigner::init()
{
    if (!m_dirPath.empty() && m_dirPath[m_dirPath.size() - 1] != '/' || m_dirPath[m_dirPath.size() - 1] != '\\') {
        m_dirPath += '/';
    }
    
    m_root = Json::objectValue;
    m_root["_schemaVersion"] = m_version;
}

bool FuncSigner::replaceChoices(std::vector<Json::Value> &arguments, std::vector<std::string> &options)
{
    bool isok = false;
    int N = (int)arguments.size() - 1;
    Json::Value & arg_type = arguments[N]["type"];
    if (arg_type.isArray() == false) {
        // LOG_WARN("[x] replaceChoices failed: arguments[type] is not array\n");
        MSG_WARN("replaceChoices failed: arguments[type] is not array");
    }

    // for ( Json::Value& type : arg_type) {
    bool is_replace = false;
    for (Json::ArrayIndex i = 0; i < arg_type.size(); ++i) {
        // LOG_INFO("[+] options type: " $ arg_type[i].size() $ "/" $ arg_type.size() $ std::endl);
        // LOG_INFO("[+] arg type: " $ arg_type[i].asString() $ std::endl);

        if (arg_type[i].size() == 0 && arg_type[i].asString() == "choices") {
            std::string tmp;
            getChoicesStr(options, tmp);
            arg_type[i] = tmp;
            isok = true;
            is_replace = true;
        }
        else {
            for (Json::ArrayIndex j = 0; j < arg_type[i].size(); ++j) {
                // LOG_INFO("[+] type: " $ arg_type.type() $ std::endl);
                if (arg_type[i][j].isString() && arg_type[i][j].asString() == "choices") {
                    std::string tmp;
                    getChoicesStr(options, tmp);
                    arg_type[i][j] = tmp;
                    isok = true;
                    is_replace = true;
                    break;
                }
            }
        }
        if (is_replace) {
            break;
        }
    }
    return isok;
}

void FuncSigner::getChoicesStr(const std::vector<std::string> &options, std::string &str)
{
    if (options.size() == 0) {
        str.clear();
        return;
    }
    str = "choices={";
    for (size_t i = 0; i < options.size(); ++i) {
        if (i != 0) {
            str += ", ";
        }
        try {
            std::stod(options[i]);
            str += options[i];
        } catch (const std::exception&) {
            str += "'";
            str += options[i];
            str += "'";
        }
    }
    str += "}";
}

bool FuncSigner::addOneFuncSign(const std::string &filepath)
{
    bool isOk = true;
    bool has_argument = false;

    /* 检查路径合法性 */ 
    std::ifstream fin(filepath, std::ios::in);
    if (!fin.is_open()) {
        // LOG_ERROR("[x] cannot open: " $ filepath $ std::endl);
        MSG_ERROR("cannot open: %v" $ filepath);
        return false;
    }
    // LOG_INFO("[+] addOneFunSign for: " $ filepath $ std::endl);
    MSG_INFO("addOneFunSign for: %v" $ filepath);

    do {
        /* 获取文件的第一个非空行，判断是否为类或函数定义文件 */
        std::string def_name;
        DefineType def_type;
        if (!isDefineFile(fin, def_name, def_type)) {
            // LOG_WARN("[!] empty file detected: " $ filepath $ std::endl);
            MSG_WARN("empty file detected: %v" $ filepath);
            isOk = false;
            break;
        }
        if (def_type == DefineType::NONE) {
            // LOG_WARN("[!] script file detected: " $ filepath $ std::endl);
            MSG_WARN("script file detected: %v" $ filepath);
            isOk = false;
            break;
        }        

        /* 检查文件名和定义名是否相同 */
        std::string def_prefix;
        if (parsePath(filepath, (int)m_dirPath.size(), def_name, def_prefix) == false) {
            // LOG_WARN("[!] The function name does not match the file name: " $ filepath  $ std::endl);
            MSG_WARN("The function name does not match the file name: %v" $ filepath);
            isOk = false;
        }

        /* 逐行读取各行 */
        StateType state = StateType::IDLE;
        std::string line;
        std::vector<Json::Value> arguments;
        std::vector<std::string> options;

        while (state != StateType::EXIT && !fin.eof()) {
            std::getline(fin, line);
            StateType cur_state = getStateFrom(line, state);

            // 修改上次选项
            if (state == StateType::OPTIONS && cur_state != state && !arguments.empty() && !options.empty()) {
                if (!replaceChoices(arguments, options)) {
                    // LOG_WARN("[!] replace choices failed\n");
                    MSG_WARN("replace choices failed");
                    isOk = false;
                }
                options.clear();
            }
            
            // LOG_INFO("[+] State: "$ getStateStr(cur_state)  $ ", Line: " $ line $ std::endl);
            MSG_INFO("State: %v, Line: %v" $ getStateStr(cur_state) $ line);
           
            if (cur_state == StateType::PARAMS) {
                
            }
            else if (cur_state == StateType::ARGUMENTS) {
                has_argument = true;
                Json::Value argument;
                cur_state = parseArgument(line, cur_state, argument);
                if (!argument.empty()) {
                    arguments.push_back(argument);
                }
            }
            else if (cur_state == StateType::OPTIONS) {
                std::string option;
                cur_state = parseOption(line, cur_state, option);
                if (!option.empty()) {
                    options.push_back(option);
                }
            }
            state = cur_state;
        }

        if (arguments.empty()) {
            // LOG_WARN("[!] arguments is empty: " $ filepath $ std::endl);
            MSG_WARN("arguments is empty: %v" $ filepath);
        }
        else {
            m_root[def_prefix] = Json::objectValue;
            m_root[def_prefix]["inputs"] = Json::arrayValue;
            for (int i = 0; i < arguments.size(); ++i) {
                if (!arguments[i].empty()) {
                    m_root[def_prefix]["inputs"].append(arguments[i]);
                }
            }
        }

    }while(0);
    
    if (has_argument == false) {
        isOk = false;
    }

    fin.close();
    if (isOk == false) {
        // LOG_INFO("[x] ------------------------ Done :(\n");
        MSG_INFO(" ------------------------ Done :(");
    }
    else {
        // LOG_INFO("[+] ------------------------ Done :)\n");
        MSG_INFO(" ------------------------ Done :)");
    }
    return isOk;
}

FuncSigner::StateType FuncSigner::parseOption(const std::string &line, FuncSigner::StateType state, std::string & option)
{
    option.clear();
    /* 检测选项标识 */
    int id = 0;
    while (id < line.size() && line[id] != m_optSym[0]) {
        id ++;
    }
    if (id >= line.size() ) {
        // LOG_WARN("[!] cannot find option symbol.\n");
        MSG_WARN("cannot find option symbol.");
        return state;
    }

    /* 选项可以用单或双引号括起(特别是选项中间存在空格), 或者不用，则默认以空格为间隔 */
    id ++;
    while (id < line.size() && (line[id] == ' ' || line[id] == '\t')) {
        id ++;
    }
    if (id >= line.size()) {
        // LOG_WARN("[!] cannot find any option.\n");
        MSG_WARN("[!] cannot find any option.");
        return state;
    }
    
    char tmp_sym = ' ';
    if (line[id] =='\'' || line[id] == '"') {
        tmp_sym = line[id];
        id ++;
    }

    int left_id = id;
    int right_id = left_id;
    while (right_id < line.size() && line[right_id] != tmp_sym) {
        right_id ++;
    }
    if (right_id >= line.size() && tmp_sym != ' ') {
        // LOG_WARN("[!] separator `" $ tmp_sym $ "` does not match\n");
        MSG_WARN("separator `%v` does not match" $ tmp_sym);
    }
    if (right_id - left_id > 0) {
        option = line.substr(left_id, right_id - left_id);
    }
    return state;
}

FuncSigner::StateType FuncSigner::parseArgument(const std::string & line, FuncSigner::StateType state, Json::Value & argument)
{
    StateType out_state = state;
    /* 确定参数标识符位置 */
    int id = 0;
    while (id < line.size() && line[id] != m_argSym[0]) {
        id ++;
    }
    if (id >= line.size()) {
        // LOG_WARN("[!] cannot find argument symbol: " $ line $ "\n");
        MSG_WARN("cannot find argument symbol: %v" $ line);
        return state;
    }

    /* 确定参数 name */
    id ++;
    while (id < line.size() && (line[id] == ' ' || line[id] == '\t')) {
        id ++;
    }
    if (id >= line.size()) {
        // LOG_WARN("[!] cannot find parameter.\n");
        MSG_WARN("cannot find parameter.");
        return state;
    }
    int left_id = id;
    int right_id = left_id;
    while (right_id < line.size() && (line[right_id] != ' ' && line[right_id] != '\t')) {
        right_id ++;
    }
    argument["name"] = line.substr(left_id, right_id - left_id);
    id = right_id;

    /* 确定参数kind */
    while (id < line.size() && line[id] != '[') {
        id ++;
    }
    if (id >= line.size()) {
        // LOG_WARN("[!] cannot find any kind `[` be set to default format): " $ line $ "\n");
        MSG_WARN("cannot find any kind `[` be set to default format): %v" $ line);
        id = right_id;
        argument["kind"] = m_default_kind; // 若无指定kind，则设置为默认值
    }
    else {
        id ++;
        left_id = id;
        right_id = left_id;
        while (right_id < line.size() && line[right_id] != ']') {
            right_id ++;
        }
        if (right_id >= line.size()) {
            // LOG_WARN("[!] parse failed: `kind` lost `]`\n");
            MSG_WARN("parse failed: `kind` lost `]`");
            return state;
        }
        std::string tmp = line.substr(left_id, right_id - left_id);
        // 去除tmp前后空格
        tmp.erase(0, tmp.find_first_not_of(" "));
        tmp.erase(tmp.find_last_not_of(" ") + 1);
        if (tmp == "R" || tmp == "r" || tmp == "required") {
            argument["kind"] = "required";
            right_id ++;
            id = right_id;
        } 
        else if (tmp == "O" || tmp == "o" || tmp == "ordered") {
            argument["kind"] = "ordered";
            right_id ++;
            id = right_id;
        } 
        else if (tmp == "N" || tmp == "n" || tmp == "namevalue") {
            argument["kind"] = "namevalue";
            right_id ++;
            id = right_id;
        }
        else {
            // LOG_WARN("[!] invalid kind: " $ tmp $ ", it will be set to required\n");
            MSG_WARN("[!] invalid kind: %v, it will be set to required" $ tmp);
            argument["kind"] = m_default_kind; // 若无指定kind，则设置为默认值
            id = left_id - 1; // 移动会到 [
        }
    }

    /* 确定参数type */
    argument["type"] = Json::arrayValue;
    while (id < line.size() && line[id] != '[') {
        id ++;
    }
    if (id >= line.size()) {
        // LOG_WARN("[!] cannot find any type `[` be set to default format): " $ line $ "\n");
        MSG_WARN("cannot find any type `[` be set to default format): %v" $ line);
        id = right_id;
        if (m_default_type.empty()) {
            argument["type"].append("numeric");
        }
        else {
            for (std::string tmp_type : m_default_type) {
                argument["type"].append(tmp_type);
            }
        }
    }
    else {
        /* 判断是否存在多级列表 */
        id ++;
        left_id = id;
        int block_left_cnt = 1;
        int block_right_cnt = 0;
        while (id < line.size() && block_left_cnt != block_right_cnt) {
            if (line[id] == '[') {
                block_left_cnt ++;
            }
            else if (line[id] == ']') {
                block_right_cnt ++;
            }
            id ++;
        }
        if (block_left_cnt != block_right_cnt) {
            // LOG_WARN("[!] invalid `type`: "$ line $ std::endl);
            MSG_WARN("invalid `type`: %v" $ line);
            return state;
        }
        id = left_id;
        
        
        if (block_left_cnt == 1) {
            // [numeric; nrows=2]
            while (line[id] != ']') {
                while (id < line.size() && ((line[id] == ' ' || line[id] == '\t') || line[id] == ';')) {
                    id ++;
                }
                left_id = id;
                right_id = left_id;
                while (right_id < line.size() && (line[right_id] != ']' && line[right_id] != ';')) {
                    right_id ++;
                }
                std::string tmp = line.substr(left_id, right_id - left_id);
                // 去除tmp前后空格
                tmp.erase(0, tmp.find_first_not_of(" "));
                tmp.erase(tmp.find_last_not_of(" ") + 1);
                if (tmp == "choices") {
                    out_state = StateType::OPTIONS;
                }
                argument["type"].append(tmp);
                id = right_id;
            }
        }
        else {
            // [[char], [string]]
            for (int i = 0; i < block_left_cnt - 1; ++i) {
                Json::Value tmpList = Json::arrayValue;
                // 移动到下一个block的`[`下一个字符
                while (id < line.size() && line[id] != '[') {
                    id ++;
                }
                if (id >= line.size()) {
                    // LOG_INFO("[!] invalid type: " $ line $ std::endl);
                    MSG_INFO("invalid type: %v" $ line);
                }
                id ++;
                // 处理 block                
                while (id < line.size() && line[id] != ']') {
                    while (id < line.size() && ((line[id] == ' ' || line[id] == '\t') || line[id] == ';')) {
                        id ++;
                    }
                    left_id = id;
                    right_id = left_id;
                    while (right_id < line.size() && (line[right_id] != ']' && line[right_id] != ';')) {
                        right_id ++;
                    }
                    std::string tmp = line.substr(left_id, right_id - left_id);
                    // 去除tmp前后空格
                    tmp.erase(0, tmp.find_first_not_of(" "));
                    tmp.erase(tmp.find_last_not_of(" ") + 1);
                    if (tmp == "choices") {
                        out_state = StateType::OPTIONS;
                    }
                    tmpList.append(tmp);
                    id = right_id + 1;
                    if (line[right_id] == ']') {
                        break;
                    }
                }
                if (!tmpList.empty()) {
                    argument["type"].append(tmpList);
                }
            }
        }
    }

    /* 确定 purpose */
    while (id < line.size() && (line[id] == ']' || (line[id] == ' ' || line[id] == '\t' || line[id] == '\r'))) {
        id ++;
    }
    int end_id = id + 1;
    while (end_id < line.size() && (line[end_id] != ' ' && line[end_id] != '\t' && line[end_id] != '\r') ) {
        end_id ++;
    }
    std::string tmp = line.substr(id, end_id - id);
    argument["purpose"] = tmp;

    return out_state;
}

bool FuncSigner::getOneWord(const std::string & line, int n, std::string & word)
{
    int start_id = 0;
    while (start_id < line.size() && line[start_id] != COMMENT_SYM) {
        start_id ++;
    }
    if (start_id >= line.size()) {
        // LOG_WARN("[!] getOneWord failed, no comment line: " $ line $ std::endl);
        MSG_WARN("getOneWord failed, no comment line: %v" $ line);
        return false;
    }
    start_id ++;
    int end_id = start_id;
    
    while (n > 0) {
        while (start_id < line.size() && (line[start_id] == ' ' || line[start_id] == '\t' || line[start_id] == '\r')) {
            start_id ++;
        }
        if (start_id >= line.size()) {
            return false;
        }
        end_id = start_id;
        while (end_id < line.size() && (line[end_id] != ' ' && line[end_id] != '\t' && line[end_id] != '\r')) {
            end_id ++;
        }
        word = line.substr(start_id, end_id - start_id);

        start_id = end_id;
        n--;
    }
    return true;
}

const char *FuncSigner::getStateStr(StateType state)
{
    if (state == StateType::IDLE) {
        return "IDLE";
    }
    else if (state == StateType::EXIT) {
        return "EXIT";
    }
    else if (state == StateType::ARGUMENTS) {
        return "ARGU";
    }
    else if (state == StateType::PARAMS) {
        return "PARA";
    }
    else if (state == StateType::OPTIONS) {
        return "OPTI";
    }
    else {
        return "Error State";
    }
}

FuncSigner::StateType FuncSigner::getStateFrom(const std::string & line, FuncSigner::StateType state)
{
    /* 遇到非注释行或空行，状态返回 EXIT */
    if (line.empty()) {
        return StateType::EXIT;
    }
    {
        int i = 0;
        while (i < line.size() && line[i] != COMMENT_SYM) {
            i++;
        }
        if (i >= line.size() || line[i] != COMMENT_SYM) {
            return StateType::EXIT;
        }
    }

    /* 尝试读取关键字 */
    std::string word;
    if (getOneWord(line, 1, word) == false) {
        // 未检查到任何单词（纯注释空行）
        // 返回原状态
        // LOG_INFO("[+] get word: none\n");
        return state;
    }
    else {
        // LOG_INFO("[+] get word: " $ word $ std::endl);
        if (word == "Params:" || word == "Params") {
            return StateType::PARAMS;
        }
        else if (word == m_argSym) {
            return StateType::ARGUMENTS;
        }
        else if (word == m_optSym && (state == StateType::OPTIONS || state == StateType::ARGUMENTS)) {
            return StateType::OPTIONS;
        }
        else {
            for (size_t i = 0; i < m_exitKeywords.size(); ++i) {
                if (word == m_exitKeywords[i]) {
                    return StateType::EXIT;
                }
            }
            // return state;
            return StateType::IDLE;
        }
    }

    return StateType::IDLE;
}

bool FuncSigner::isClassFolder(const std::string & filepath)
{
    bool has_a = false;
    int pos_a = -1;
    for (int i = 0; i < filepath.size(); ++i) {
        if (filepath[i] == '@') {
            has_a = true;
            pos_a = i;
            break;
        }
    }

    if (has_a) {
        int cnt = 0;
        for (int i = pos_a; i < filepath.size(); ++i) {
            if (filepath[i] == '/' || filepath[i] == '\\') {
                cnt ++;
            }
        }
        if (cnt <= 1) {
            has_a = false;
        } 
    }
    
    return has_a;
}
